#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <signal.h>
#include <stdint.h>

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 12345

// 全局退出标志（volatile确保多线程可见，sig_atomic_t确保信号处理中安全访问）
static volatile sig_atomic_t g_quit = 0;

// 信号处理函数：捕获SIGINT(Ctrl+C)和SIGTERM信号
static void handle_signal(int signo) {
    g_quit = 1;
    // 向标准输入写一个换行，唤醒可能阻塞的getline
    if (signo == SIGINT) {
        write(STDIN_FILENO, "\n", 1);
    }
}

// 完整读取指定长度的数据
static ssize_t read_full(int fd, void *buf, size_t count) {
    size_t off = 0;  // 已读取的字节数（偏移量）
    ssize_t n;       // 每次read实际读取的字节数

    while (off < count && !g_quit) {  // 检查退出标志
        n = read(fd, (char*)buf + off, count - off);
        if (n < 0) {
            if (errno == EINTR) continue;  // 被信号打断，重试
            return -1;                     // 其他错误
        }
        if (n == 0) return off;;  // 对方关闭连接
        off += n;
    }

    return off;  // 返回实际读取的字节数（可能小于count）
}

int main() {
    int sock = -1;
    char *line = NULL;
    size_t line_len = 0;

    // 注册信号处理
    struct sigaction sa = {0};
    sa.sa_handler = handle_signal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGINT, &sa, NULL) == -1 || 
        sigaction(SIGTERM, &sa, NULL) == -1) {
        perror("sigaction failed");
        exit(EXIT_FAILURE);
    }

    // 创建socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 配置服务器地址
    struct sockaddr_in srv_addr;
    memset(&srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_port = htons(SERVER_PORT);
    if (inet_pton(AF_INET, SERVER_IP, &srv_addr.sin_addr) <= 0) {
        perror("invalid server address");
        close(sock);
        exit(EXIT_FAILURE);
    }

    // 连接服务器
    if (connect(sock, (struct sockaddr*)&srv_addr, sizeof(srv_addr)) < 0) {
        perror("connection failed");
        close(sock);
        exit(EXIT_FAILURE);
    }
    printf("Connected to %s:%d\n", SERVER_IP, SERVER_PORT);
    printf("Enter message (Ctrl+D or Ctrl+C to exit)\n");

    // 主交互循环
    while (!g_quit) {
        printf("> ");
        fflush(stdout);

        // 读取用户输入
        ssize_t n = getline(&line, &line_len, stdin);
        

        if (n < 0) {
            if (g_quit) break;  // 因信号退出
            if (feof(stdin)) {  // 用户输入Ctrl+D
                printf("\n");
                break;
            }
            perror("getline failed");
            break;
        }

        // 处理输入（移除换行符）
        size_t body_len = strcspn(line, "\r\n");
        line[body_len] = '\0';

        // 构建消息（2字节类型 + 2字节长度 + 正文）
        uint16_t msg_type = 1;
        uint16_t net_type = htons(msg_type);
        uint16_t net_len = htons((uint16_t)body_len);
        size_t total_len = sizeof(net_type) + sizeof(net_len) + body_len;
        uint8_t *send_buf = malloc(total_len);
        if (!send_buf) {
            perror("malloc failed");
            break;
        }

        // 填充发送缓冲区
        memcpy(send_buf, &net_type, sizeof(net_type));
        memcpy(send_buf + 2, &net_len, sizeof(net_len));
        memcpy(send_buf + 4, line, body_len);

        // 发送数据
        if (write(sock, send_buf, total_len) != (ssize_t)total_len) {
            perror("send failed");
            free(send_buf);
            break;
        }
        free(send_buf);
        fflush(stdout);
        // 接收服务器回复头部
        uint16_t resp_type, resp_len;
        if (read_full(sock, &resp_type, sizeof(resp_type)) != sizeof(resp_type) ||
            read_full(sock, &resp_len, sizeof(resp_len)) != sizeof(resp_len)) {
            fprintf(stderr, "connection closed or read header failed\n");
            break;
        }
        resp_type = ntohs(resp_type);
        resp_len = ntohs(resp_len);

        // 接收回复正文
        uint8_t *resp_body = malloc(resp_len + 1);  // +1 用于字符串结束符
        if (!resp_body) {
            perror("malloc response body failed");
            break;
        }
        if (read_full(sock, resp_body, resp_len) != resp_len) {
            fprintf(stderr, "read response body failed\n");
            free(resp_body);
            break;
        }
        resp_body[resp_len] = '\0';  // 确保字符串终止

        // 显示回复
        printf("<< type=%u, len=%u, data=\"%s\"\n",
               resp_type, resp_len, resp_body);

        free(resp_body);
    }

    // 优雅清理资源
    printf("Cleaning up...\n");
    free(line);           // 释放getline分配的缓冲区
    if (sock != -1) {
        close(sock);       // 关闭socket
        printf("Connection closed\n");
    }

    return 0;
}
